﻿//========================================================= 
/**@file CommandWorker.h
 * @brief 用于在后台异步处理命令的队列
 * 
 * @date 2017-06-12   22:25:18
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_COMMANDWORKER_H_
#define _LIBZHOUYB_COMMANDWORKER_H_
//--------------------------------------------------------- 
#include "../CommandRunner.h"
#include "../CommandInstaller.h"

#include "../../../container/async.h"
using zhou_yb::container::async_mutex;
using zhou_yb::container::async_lock;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
namespace async {
//--------------------------------------------------------- 
/**
 * @brief 基于CommandSetter的命令并发调度器
 * @date 2017-06-24 11:18
 */
class CommandDispatcher : public RefObject
{
    DisableObjConsturctCopyBehavior(CommandDispatcher)
protected:
    string _currentCmd;
    async_mutex _mutex;
    CommandSetter _setter;
public:
    CommandDispatcher() {}
    CommandDispatcher(const CommandSetter& setter)
    {
        _setter = setter;
    }
    inline void Set(const CommandSetter& setter)
    {
        ASYNC_LOCK(_mutex);
        _setter.Clear();
        _setter = setter;
    }
    LC_CMD_METHOD(TryLock)
    {
        return _mutex.try_lock();
    }
    LC_CMD_METHOD(Lock)
    {
        return _mutex.lock();
    }
    LC_CMD_METHOD(Unlock)
    {
        return _mutex.unlock();
    }
    /// 返回对Settet的只读引用
    inline const CommandSetter& Setter() const
    {
        return _setter;
    }
    /**
     * @brief 尝试执行指定名称的命令
     * @date 2017-06-30 19:13
     * 
     * @param [in] sCmd 需要执行的命令
     * @param [in] arg 执行命令的参数
     * @param [out] rlt 执行命令的结果
     * 
     * @return DeviceError::ErrorCode 错误码
     * - 错误码:
     *  - DeviceError::DevIsBusyErr 模块忙,正在执行其他命令
     *  - DeviceError::ArgIsNullErr 指定名称的命令不存在
     *  - DeviceError::OperatorErr 调用失败
     *  - DeviceError::Success 调度成功
     * .
     */
    DeviceError::ErrorCode TryCall(const char* sCmd, IStringArguments& arg, IStringArguments& rlt)
    {
        if(!_mutex.try_lock())
            return DeviceError::DevIsBusyErr;
        Ref<ComplexCommand> complexCmd = _setter.LookUp(sCmd);
        _mutex.unlock();
        return TryCall(complexCmd, arg, rlt);
    }
    /// 尝试执行指定的命令
    DeviceError::ErrorCode TryCall(Ref<ComplexCommand> cmd, IStringArguments& arg, IStringArguments& rlt)
    {
        if(!_mutex.try_lock())
            return DeviceError::DevIsBusyErr;
        if(cmd.IsNull())
        {
            _mutex.unlock();
            return DeviceError::ArgIsNullErr;
        }
        _currentCmd = cmd->Name();
        bool bOK = cmd->OnCommand(arg, rlt);
        _currentCmd = "";
        _mutex.unlock();
        return bOK ? DeviceError::Success : DeviceError::OperatorErr;
    }
    /// 返回当前正在执行的任务名称,TryCall失败时可获取当前任务名称
    inline const string& Current() const
    {
        return _currentCmd;
    }
};
//--------------------------------------------------------- 
/**
 * @brief 基于CommandRunner的命令调度器
 * @date 2017-06-24 11:23
 *
 * 调度原理:
 * 1.将命令分为Except命令和功能命令
 * 2.Except命令为设置类命令,不涉及到设备
 * 3.功能命令不能冲突,每组命令之间(CommandSetter)通过一个锁进行异步
 * 4.运行时,以CommandSetter为一组进行调度
 */
class CommandWorker : public CommandRunner
{
public:
    /// 调度器枚举类型
    typedef MapArguments<string, CommandDispatcher*>::EnumeratorType EnumeratorType;
    /// 格式化错误信息
    static string FormatErr(DeviceError::ErrorCode err, const char* sModule, const char* sCmd, const char* currentCmd = NULL)
    {
        string module = _strput(sModule);
        size_t len = module.length();
        switch(err)
        {
        case DeviceError::Success:
            return "";
        case DeviceError::DevIsBusyErr:
            if(!_is_empty_or_null(currentCmd))
            {
                if(len > 0)
                {
                    module += "::";
                }
                module += currentCmd;
                module += "忙,";
                module += _strput(sModule);
            }
            if(len > 0)
            {
                module += "::";
            }
            module += _strput(sCmd);
            module += "调用失败";
            break;
        case DeviceError::ArgIsNullErr:
            module += "::";
            module += _strput(sCmd);
            module += "不存在";
            break;
        case DeviceError::OperatorErr:
            module += "::";
            module += _strput(sCmd);
            module += "返回失败";
            break;
        case DeviceError::ArgRangeErr:
            module += "模块不存在";
            break;
        default:
            break;
        }
        return module;
    }
protected:
    list_t<CommandDispatcher> _workObjItems;
    MapArguments<string, CommandDispatcher*> _workItems;
    async_mutex _mutex;
    string _currentCmd;
    /// 分析Collection,配置异步命令分组
    void _AsyncCollection(const string& name, CommandCollection& collection)
    {
        LOGGER(LoggerAdapter& _log = this->_log);
        CommandSetter setter;
        CommandSetter exceptSetter;
        Ref<ComplexCommand> complexCmd;
        list_t<CommandDispatcher>::iterator workItr;
        setter.Set(collection).All();
        exceptSetter.Set(collection);

        CommandInstaller::ExceptSysCommand(setter, &exceptSetter);
        CommandInstaller::ExceptCommand(setter, &exceptSetter);

        LOGGER(_log << "Module:<" << name << ">\n";
        _log.WriteLine("Setter:");
        CommandSetter::EnumeratorType enumer = setter.GetEnumerator();
        while(enumer.MoveNext())
        {
            _log << enumer.Current()->Name() << " ";
        }
        _log.WriteLine();
        if(exceptSetter.Count() > 0)
        {
            _log.WriteLine("Except Setter:");
            enumer = exceptSetter.GetEnumerator();
            while(enumer.MoveNext())
            {
                _log << enumer.Current()->Name() << " ";
            }
        }
        _log.WriteLine());

        workItr = _workObjItems.push_back();
        workItr->Set(setter);
        _workItems.Put(name, &(*workItr));

        if(exceptSetter.Count() < 1)
            return;

        workItr = _workObjItems.push_back();
        workItr->Set(exceptSetter);
        string exceptName = name;
        exceptName += ".Except";
        _workItems.Put(exceptName, &(*workItr));
        return;
    }
    /// _logErr错误码
    bool _HandleErr(DeviceError::ErrorCode err, const char* sModule, const char* sCmd, const char* currentCmd = NULL)
    {
        if(DeviceError::IsSuccess(err))
            return true;
        string errMsg = FormatErr(err, sModule, sCmd, currentCmd);
        ResetErr();
        _logErr(err, errMsg.c_str());
        return false;
    }
    /// 查找模块中指定的命令(包括Except集合)
    CommandDispatcher* _Find(const char* sModule, const char* sCmd, bool* pIsExcept = NULL)
    {
        string module = _strput(sModule);
        CommandDispatcher* pDispatcher = NULL;
        _workItems.Get(module, pDispatcher);
        if(pDispatcher == NULL)
            return NULL;
        // 如果查找不到,则继续在Except中查找
        if(pDispatcher->Setter().Seek(sCmd).IsNull())
        {
            pDispatcher = NULL;
            module += ".Except";
            _workItems.Get(module, pDispatcher);

            if(pIsExcept != NULL)
            {
                (*pIsExcept) = true;
            }
        }
        return pDispatcher;
    }
    bool _PutErr(DeviceError::ErrorCode err, const char* sModule, const char* sCmd, IStringArguments& rlt, const char* currentCmd = NULL)
    {
        bool isOK = _HandleErr(err, sModule, sCmd, currentCmd);
        if(isOK)
        {
            return true;
        }

        StringArguments arg;
        LastError(arg, rlt);
        return false;
    }
public:
    CommandWorker() : CommandRunner() {}
    /// 获取调度器枚举器
    EnumeratorType GetEnumerator()
    {
        return _workItems.GetEnumerator();
    }
    /**
     * @brief 解析CommandRunner异步初始化
     * @date 2017-07-01 15:22
     */
    size_t OnWork()
    {
        ASYNC_LOCK(_mutex);
        LOG_FUNC_NAME();
        _workItems.Clear();

        CommandRunner::MapEnumeratorType enumer = CommandRunner::_items.GetEnumerator();
        CommandCollection* pCollection = NULL;
        string name = "";
        size_t count = 1;
        _AsyncCollection(name, *this);
        while(enumer.MoveNext())
        {
            name = enumer.Current().Key;
            pCollection = enumer.Current().Value;
            _AsyncCollection(name, *pCollection);

            ++count;
        }
        return _logRetValue(count);
    }
    /**
     * @brief 同步调用(支持在线程中调用)
     * @date 2017-07-01 15:27
     * 
     * @param [in] sModule 需要操作的模块名
     * @param [in] sCmd 需要调用的命令
     * @param [in] arg 调用时的参数
     * @param [out] rlt 调用后的结果
     * 
     * @return bool 是否调度成功
     */
    bool Call(const char* sModule, const char* sCmd, IStringArguments& arg, IStringArguments& rlt)
    {
        DeviceError::ErrorCode err = DeviceError::ArgRangeErr;
        CommandDispatcher* pDispatcher = NULL;
        {
            ASYNC_LOCK(_mutex);
            pDispatcher = _Find(sModule, sCmd);
        }
        if(pDispatcher != NULL)
        {
            err = pDispatcher->TryCall(sCmd, arg, rlt);
        }
        ASYNC_LOCK(_mutex);
        string currentCmd = pDispatcher->Current();
        return _HandleErr(err, sModule, sCmd, currentCmd.c_str());
    }
    /**
     * @brief 同步调用(支持在线程中调用,附带错误信息)
     * @date 2017-07-10 15:40
     * 
     * @param [in] sModule 需要调用的模块名
     * @param [in] sCmd 需要调用的命令
     * @param [in] arg 调用的参数
     * @param [out] rlt 调用的结果
     */
    bool OnCall(const char* sModule, const char* sCmd, IStringArguments& arg, IStringArguments& rlt)
    {
        LOG_FUNC_NAME();
        if(!_mutex.try_lock())
        {
            return _PutErr(DeviceError::DevIsBusyErr, sModule, sCmd, rlt, "Worker");
        }
        string module = _strput(sModule);
        string cmd = _strput(sCmd);

        LOGGER(_log << "Module:<" << module << ">\n";
        _log << "Command:<" << cmd << ">\n");

        DeviceError::ErrorCode err = DeviceError::UnKnownErr;
        bool bOK = false;
        bool isExcept = false;
        CommandDispatcher* pDispatcher = _Find(module.c_str(), cmd.c_str(), &isExcept);
        ResetError(arg, rlt);

        if(pDispatcher != NULL)
        {
            LOGGER(_log << "TryCall:<" << cmd << ">\n");
            if(!isExcept)
            {
                // 保存上次操作的命令名称
                _currentCmd = module;
                if(module.length() > 0)
                {
                    _currentCmd += "::";
                }
                _currentCmd = cmd;
            }
            _mutex.unlock();
            err = pDispatcher->TryCall(cmd.c_str(), arg, rlt);
            _mutex.lock();
            LOGGER(_log << cmd << "->Call:<" << DeviceError::ToString(err) << ">\n");
            bOK = DeviceError::IsSuccess(err);
            if(err == DeviceError::OperatorErr)
            {
                LOGGER(_log.WriteLine("TryCall:LastError"));
                pDispatcher->TryCall("LastError", arg, rlt);
                // 发生错误时,底层没有正常设置错误码
                if(DeviceError::IsSuccess(rlt["CODE"].To<int>(err)))
                {
                    LOGGER(_log.WriteLine("Reset LastError=OperatorErr"));
                    StringArguments::Set(rlt, "CODE", ArgConvert::ToString(err));
                    StringArguments::Set(rlt, "MSG", FormatErr(err, sModule, sCmd));
                }
            }
            else if(!bOK)
            {
                _HandleErr(err, module.c_str(), cmd.c_str(), pDispatcher->Current().c_str());
                LastError(arg, rlt);
            }
            string sCode = "";
            if(!rlt.Get("CODE", sCode))
            {
                LOGGER(_log << "Put CODE:<" << DeviceError::ToString(err) << ">\n");
                rlt.Put("CODE", ArgConvert::ToString(static_cast<int>(err)));
            }
            _currentCmd = "";
        }
        else
        {
            _HandleErr(DeviceError::ArgRangeErr, module.c_str(), cmd.c_str());
            LastError(arg, rlt);
        }
        _mutex.unlock();
        return _logRetValue(bOK);
    }
};
//--------------------------------------------------------- 
} // namespace async
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_COMMANDWORKER_H_
//========================================================= 